Аналитика в Яндекс.Дзен

Оглавление

Описание проекта

Аналитики в Яндекс.Дзене занимаются анализом пользовательского взаимодействия с карточками статей. Каждую карточку определяют её тема и источник (у него тоже есть тема). Пользователей системы характеризует возрастная категория. Есть три способа взаимодействия пользователей с системой:

  • карточка отображена для пользователя (show);
  • пользователь кликнул на карточку (click);
  • пользователь просмотрел статью карточки (view).

Каждую неделю необходимо ответить на одни и те же вопросы:

  1. Сколько взаимодействий пользователей с карточками происходит в системе с разбивкой по темам карточек?
  2. Как много карточек генерируют источники с разными темами?
  3. Как соотносятся темы карточек и темы источников?

Цель и задачи проекта

Цель проекта - анализ взаимодействия пользователей с карточками Яндекс.Дзен.


Для этого необходимо:

  1. выгрузить данные из базы;
  2. в Tableau Public сформировать дашборд в соответствии с макетом и опубликовать его в открытом доступе;
  3. подготовить презентацию с отчетом для ответа на поставленные вопросы.

Описание данных

  • record_id - порядковый номер записи в таблице;
  • item_topic - тема карточек;
  • source_topic - тема источников;
  • age_segment - возрастная группа;
  • dt - дата и время взаимодействия пользователей с системой;
  • visits - количество взаимодействий пользователей с системой.

Выгрузка, изучение и подготовка данных

In [1]:
# импортируем библиотеки
import pandas as pd
from sqlalchemy import create_engine
from datetime import datetime
import plotly
from plotly import graph_objects as go
import plotly.figure_factory as ff
import plotly.io as pio
pio.templates.default = 'seaborn'
In [2]:
# %%HTML
# <style type="text/css">
# table.dataframe td, table.dataframe th {
#     border: 1px  black solid !important;
#   color: black !important;
# }
In [3]:
# создадим коннекцию к базе
# db_config = {'user' : 'praktikum_student', # имя пользователя
#              'pwd' : 'Sdf4$2;d-d30pp', # пароль
#              'host' : 'rc1b-wcoijxj3yxfsf3fs.mdb.yandexcloud.net',
#              'port' : 6432, # порт подключения
#              'db' : 'data-analyst-zen-project-db'} # название базы данных
# connection_string = 'postgresql://{}:{}@{}:{}/{}'.format(db_config['user'],
#                                                          db_config['pwd'],
#                                                          db_config['host'],
#                                                          db_config['port'],
#                                                          db_config['db'])
# engine = create_engine(connection_string) 
In [4]:
# выполним sql-запрос
# query = ''' 
#             SELECT *
#             FROM dash_visits
#         '''
# dash_visits = pd.io.sql.read_sql(query, con = engine)
# dash_visits.head()
In [5]:
# сохраним выгруженную таблицу в формате "csv"
# dash_visits.to_csv('dash_visits.csv', index=False)
In [6]:
dash_visits = pd.read_csv('dash_visits.csv')
dash_visits.head()
Out[6]:
record_id item_topic source_topic age_segment dt visits
0 1040597 Деньги Авто 18-25 2019-09-24 18:32:00 3
1 1040598 Деньги Авто 18-25 2019-09-24 18:35:00 1
2 1040599 Деньги Авто 18-25 2019-09-24 18:54:00 4
3 1040600 Деньги Авто 18-25 2019-09-24 18:55:00 17
4 1040601 Деньги Авто 18-25 2019-09-24 18:56:00 27
In [7]:
# посмотрим сводную информацию таблицы
dash_visits.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 30745 entries, 0 to 30744
Data columns (total 6 columns):
 #   Column        Non-Null Count  Dtype 
---  ------        --------------  ----- 
 0   record_id     30745 non-null  int64 
 1   item_topic    30745 non-null  object
 2   source_topic  30745 non-null  object
 3   age_segment   30745 non-null  object
 4   dt            30745 non-null  object
 5   visits        30745 non-null  int64 
dtypes: int64(2), object(4)
memory usage: 1.4+ MB

В таблице 30745 строк, 6 столбцов, тип данных у четырех столбцов строковый, у двух - целочисленный. В столбце dt значения даты и времени взаимодействия необходимо привести к формату datetime.

In [8]:
# посмотрим на уникальные значения по столбцам таблицы
for column in dash_visits.columns:
    if (dash_visits[column].dtype == 'object'):        
        print(column)
        print()
        print(dash_visits[column].unique())
        print('Количество уникальных значений',
              dash_visits[column].nunique())
        print()
        print()
item_topic

['Деньги' 'Дети' 'Женская психология' 'Женщины' 'Здоровье' 'Знаменитости'
 'Интересные факты' 'Искусство' 'История' 'Красота' 'Культура' 'Наука'
 'Общество' 'Отношения' 'Подборки' 'Полезные советы' 'Психология'
 'Путешествия' 'Рассказы' 'Россия' 'Семья' 'Скандалы' 'Туризм' 'Шоу'
 'Юмор']
Количество уникальных значений 25


source_topic

['Авто' 'Деньги' 'Дети' 'Еда' 'Здоровье' 'Знаменитости' 'Интерьеры'
 'Искусство' 'История' 'Кино' 'Музыка' 'Одежда' 'Полезные советы'
 'Политика' 'Психология' 'Путешествия' 'Ремонт' 'Россия' 'Сад и дача'
 'Сделай сам' 'Семейные отношения' 'Семья' 'Спорт' 'Строительство'
 'Технологии' 'Финансы']
Количество уникальных значений 26


age_segment

['18-25' '26-30' '31-35' '36-40' '41-45' '45+']
Количество уникальных значений 6


dt

['2019-09-24 18:32:00' '2019-09-24 18:35:00' '2019-09-24 18:54:00'
 '2019-09-24 18:55:00' '2019-09-24 18:56:00' '2019-09-24 18:57:00'
 '2019-09-24 18:58:00' '2019-09-24 18:59:00' '2019-09-24 19:00:00'
 '2019-09-24 18:29:00' '2019-09-24 18:30:00' '2019-09-24 18:31:00'
 '2019-09-24 18:52:00' '2019-09-24 18:33:00' '2019-09-24 18:53:00'
 '2019-09-24 18:28:00' '2019-09-24 18:34:00']
Количество уникальных значений 17


Всего 25 уникальных значений тем карточек, 26 - тем источников, пользователи распределены на 6 возрастных групп. Имеется информация за 24 сентября 2019 года, период с 18 часов 28 минут по 19 часов, при этом данные с 18 часов 36 минут по 18 часов 51 минуту отсутствуют.

In [9]:
# посмотрим статистичускую информацию количества взаимодействий пользователей с системой
dash_visits['visits'].describe()
Out[9]:
count    30745.000000
mean        10.089673
std         19.727601
min          1.000000
25%          1.000000
50%          3.000000
75%         10.000000
max        371.000000
Name: visits, dtype: float64

Минимальное количество взаимодействий с группировкой по темам карточек, темам источников и возрастным группам - 1, максимальное - 371, среднее арифметическое - 10, медиана - 3.

In [10]:
# приведем значения даты и времени взаимодействия к формату `datetime`
dash_visits['dt'] = pd.to_datetime(dash_visits['dt'])
dash_visits['dt'].unique()
Out[10]:
array(['2019-09-24T18:32:00.000000000', '2019-09-24T18:35:00.000000000',
       '2019-09-24T18:54:00.000000000', '2019-09-24T18:55:00.000000000',
       '2019-09-24T18:56:00.000000000', '2019-09-24T18:57:00.000000000',
       '2019-09-24T18:58:00.000000000', '2019-09-24T18:59:00.000000000',
       '2019-09-24T19:00:00.000000000', '2019-09-24T18:29:00.000000000',
       '2019-09-24T18:30:00.000000000', '2019-09-24T18:31:00.000000000',
       '2019-09-24T18:52:00.000000000', '2019-09-24T18:33:00.000000000',
       '2019-09-24T18:53:00.000000000', '2019-09-24T18:28:00.000000000',
       '2019-09-24T18:34:00.000000000'], dtype='datetime64[ns]')
In [11]:
# для удобства визуализации преобразуем значения даты и времени взаимодействия
dash_visits['dt'] = dash_visits['dt'].apply(lambda x: x.strftime('%H-%M'))
dash_visits['dt'].unique()
Out[11]:
array(['18-32', '18-35', '18-54', '18-55', '18-56', '18-57', '18-58',
       '18-59', '19-00', '18-29', '18-30', '18-31', '18-52', '18-33',
       '18-53', '18-28', '18-34'], dtype=object)
In [12]:
# определим количество пропущенных значений в таблице
dash_visits.isnull().sum()
Out[12]:
record_id       0
item_topic      0
source_topic    0
age_segment     0
dt              0
visits          0
dtype: int64
In [13]:
# посчитаем количество дубликатов
dash_visits.duplicated().sum()
Out[13]:
0

Пропущенные значения и дубликаты отсутствуют.

Вывод

В целях выгрузки данных:

  • создана коннекция к базе;
  • выполнен sql-запрос;
  • сохранена выгруженная таблица в формате "csv".

При изучении таблицы с данными установлено:

  • в таблице 30745 строк, 6 столбцов, пропущенные значения и дубликаты отсутствуют;
  • тип данных у четырех столбцов строковый, у двух - целочисленный;
  • в столбце dt значения даты и времени взаимодействия необходимо привести к формату datetime;
  • всего имеется 25 уникальных значений тем карточек, 26 - тем источников, пользователи распределены на 6 возрастных групп;
  • имеется информация за 24 сентября 2019 года, период с 18 часов 28 минут по 19 часов, при этом данные с 18 часов 36 минут по 18 часов 51 минуту отсутствуют;
  • минимальное количество взаимодействий с группировкой по темам карточек, темам источников и возрастным группам - 1, максимальное - 371, среднее арифметическое - 10, медиана - 3.

Для подготовки данных:

  1. в столбце dt значения даты и времени взаимодействия привели к формату datetime;
  2. в столбце dt для удобства визуализации преобразовали значения даты и времени взаимодействия.

Формирование дашборда

В Tableau Public сформируем дашборд в соответствии с приведенным макетом.

image.png

По ссылке дашборд опубликован в открытом доступе.

Подготовка презентации

Учитывая, что в Tableau Public невозможно сохранить построенные графики, проведем анализ данных для подготовки презентации в Jupyter Notebook.

In [14]:
# посчитаем общее количество взаимодействий пользователей
dash_visits['visits'].sum()
Out[14]:
310207

Всего пользователями осуществлено 310207 взаимодействий.

In [15]:
# создадим таблицу с количеством взаимодействий пользователей по времени
visits_time = dash_visits.groupby('dt')\
                         .agg(visits_count = ('visits', 'sum'))\
                         .reset_index()
visits_time
Out[15]:
dt visits_count
0 18-28 835
1 18-29 1817
2 18-30 2442
3 18-31 2592
4 18-32 2587
5 18-33 1726
6 18-34 763
7 18-35 196
8 18-52 1112
9 18-53 2057
10 18-54 14140
11 18-55 32696
12 18-56 54168
13 18-57 60759
14 18-58 61247
15 18-59 53366
16 19-00 17704
In [16]:
# построим график количества взаимодействий пользователей по времени
fig = go.Figure()
fig.add_trace(go.Scatter(x = visits_time['dt'],
                         y = visits_time['visits_count'],
                         mode = 'lines + markers + text',
                         text = visits_time['visits_count'],
                         textposition = 'top center',
                         textfont = dict(family = 'sans serif', size = 18, color = 'crimson'),
                         line = dict(color = 'royalblue', width = 4),
                         marker = dict(color = 'royalblue', size = 10)))
fig.update_layout(yaxis = dict(range = [-1000, 66000]),
                  title = 'Количество взаимодействий пользователей по времени',
                  title_font = dict(family = 'sans serif', size = 20),
                  xaxis_title = 'Время',
                  yaxis_title = 'Количество взаимодействий',
                  showlegend = False,
                  margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.add_annotation(x = '18-35', y = 6000,
                   text='С 18-36 до 18-51 данные отсутствуют',
                   showarrow = True,
                   arrowhead = 1,
                   arrowsize = 1,
                   arrowwidth = 2,
                   arrowcolor = 'black',
                   font = dict(family = 'sans serif', size = 14, color = 'white'),
                   align = 'center',
                   bordercolor = 'royalblue',
                   borderwidth = 2,
                   borderpad = 4,
                   bgcolor = 'crimson',
                   opacity = 0.8)
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Время: %{x}<br>Взаимодействий: %{y}')
fig.show()

Максимальное количество взаимодействий осуществлено пользователями с 18 часов 56 минут по 18 часов 59 минут.

In [17]:
# создадим таблицу с количеством взаимодействий пользователей по темам карточек
item_visits = dash_visits.groupby('item_topic')\
                         .agg(visits_count = ('visits', 'sum'))\
                         .sort_values(by = 'visits_count', ascending = False)\
                         .reset_index()                         
item_visits.head(10)
Out[17]:
item_topic visits_count
0 Наука 21736
1 Отношения 20666
2 Интересные факты 19942
3 Общество 19640
4 Подборки 17772
5 Россия 16966
6 Полезные советы 15435
7 История 15389
8 Семья 11897
9 Женщины 11499

Более 15000 взаимодействий осуществлено по 8 темам карточек.

In [18]:
# построим график количества взаимодействий пользователей по темам карточек
fig = go.Figure()
colors = ['royalblue',] * 26
colors[0:9] = ['midnightblue',] * 8
fig.add_trace(go.Bar(x = item_visits['item_topic'],
                     y = item_visits['visits_count'],
                     marker_color = colors,
                     text = item_visits['visits_count'],
                     textposition = 'outside',
                     textfont = dict(family = 'sans serif', size = 11, color = 'crimson')))
fig.update_layout(title = 'Количество взаимодействий пользователей по темам карточек',
                  title_font = dict(family = 'sans serif', size = 20),
                  xaxis_title = 'Тема карточек',
                  yaxis_title = 'Количество взаимодействий',
                  showlegend = False,
                  margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Тема: %{x}<br>Взаимодействий: %{y}')
fig.show()

Наибольшее количество взаимодействий по карточкам с темами "Наука", "Отношения", "Интересные факты" и "Общество".

In [19]:
# создадим таблицу с количеством взаимодействий пользователей по темам источников
source_visits = dash_visits.groupby('source_topic')\
                           .agg(visits_count = ('visits', 'sum'))\
                           .sort_values(by = 'visits_count', ascending = False)\
                           .reset_index()                         
source_visits.head(10)
Out[19]:
source_topic visits_count
0 Семейные отношения 33309
1 Россия 29831
2 Полезные советы 27412
3 Путешествия 24124
4 Знаменитости 23945
5 Кино 20084
6 Дети 15243
7 История 14628
8 Семья 13896
9 Здоровье 12831

Более 20000 взаимодействий осуществлено из источников по 6 темам.

In [20]:
# построим график количества взаимодействий пользователей по темам источников
fig = go.Figure()
colors = ['royalblue',] * 27
colors[0:7] = ['midnightblue',] * 6
fig.add_trace(go.Bar(x = source_visits['source_topic'],
                     y = source_visits['visits_count'],
                     marker_color = colors,
                     text = source_visits['visits_count'],
                     textposition = 'outside',
                     textfont = dict(family = 'sans serif', size = 11, color = 'crimson')))
fig.update_layout(title = 'Количество взаимодействий пользователей по темам источников',
                  title_font = dict(family = 'sans serif', size = 20),
                  xaxis_title = 'Тема источников',
                  yaxis_title = 'Количество взаимодействий',
                  showlegend = False,
                  margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Тема: %{x}<br>Взаимодействий: %{y}')
fig.show()

Наибольшее количество взаимодействий у источников с темами "Семейные отношения", "Россия" и "Полезные советы".

In [21]:
# создадим таблицу с количеством взаимодействий пользователей по возрастным группам
age_visits = dash_visits.groupby('age_segment')\
                        .agg(visits_count = ('visits', 'sum'))\
                        .sort_values(by = 'visits_count', ascending = False)\
                        .reset_index()                         
age_visits
Out[21]:
age_segment visits_count
0 18-25 131010
1 26-30 60311
2 31-35 53763
3 36-40 38166
4 41-45 16263
5 45+ 10694
In [22]:
# построим график количества взаимодействий пользователей по возрастным группам
fig = go.Figure()
colors = ['royalblue',] * 6
colors[0] = 'midnightblue'
fig.add_trace(go.Bar(x = age_visits['age_segment'],
                     y = age_visits['visits_count'],
                     marker_color = colors,
                     text = age_visits['visits_count'],
                     textposition = 'outside',
                     textfont = dict(family = 'sans serif', size = 16, color = 'crimson')))
fig.update_layout(title = 'Количество взаимодействий пользователей по возрастным группам',
                  title_font = dict(family = 'sans serif', size = 20),
                  xaxis_title = 'Возрастная группа',
                  yaxis_title = 'Количество взаимодействий',
                  showlegend = False,
                  margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Возрастная группа: %{x}<br>Взаимодействий: %{y}')
fig.show()

Наибольшее количество взаимодействий у возрастной группы от 18 до 25 лет.

In [23]:
# создадим таблицу с количеством взаимодействий пользователей по темам карточек и времени
item_visits_time = dash_visits.groupby(['dt', 'item_topic'])\
                              .agg(visits_count = ('visits', 'sum'))\
                              .reset_index()
item_visits_time.head()
Out[23]:
dt item_topic visits_count
0 18-28 Деньги 24
1 18-28 Дети 32
2 18-28 Женская психология 19
3 18-28 Женщины 27
4 18-28 Здоровье 25
In [24]:
# построим график количества взаимодействий пользователей по темам карточек и времени с абсолютными значениями
fig = go.Figure()
for item in item_visits_time['item_topic'].unique():
    fig.add_trace(go.Scatter(x = item_visits_time.query('item_topic == @item')['dt'],
                             y = item_visits_time.query('item_topic == @item')['visits_count'],
                             mode = 'lines',
                             name = item,
                             stackgroup = 'one'))
fig.update_layout(yaxis = dict(range = [7, 65000]),
                  title = 'Количество взаимодействий пользователей по темам карточек и времени (абсолютные значения)',
                  title_font = dict(family = 'sans serif', size = 20),
                  xaxis_title = 'Время',
                  yaxis_title = 'Количество взаимодействий',
                  showlegend = False,
                  margin = dict(l = 0, r = 20, t = 70, b = 0))
def annotation(y, text):
    fig.add_annotation(x = '18-57',
                       y = y,
                       text = '              ' + text,
                       showarrow = False)
annotation_dict = {26000 : 'Наука',
                   34000 : 'Отношения',
                   13000 : 'Интересные факты',
                   30000 : 'Общество',
                   38000 : 'Подборки',
                   50000 : 'Россия',
                   41000 : 'Полезные советы',
                   19000 : 'История'}
for k, v in annotation_dict.items():
    annotation(k, v)
fig.add_annotation(x = '18-35', y = 4000,
                   text='С 18-36 до 18-51 данные отсутствуют',
                   showarrow = True,
                   arrowhead = 1,
                   arrowsize = 1,
                   arrowwidth = 2,
                   arrowcolor = 'black',
                   font = dict(family = 'sans serif', size = 14, color = 'white'),
                   align = 'center',
                   bordercolor = 'royalblue',
                   borderwidth = 2,
                   borderpad = 4,
                   bgcolor = 'crimson',
                   opacity = 0.8)
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))                   
fig.update_traces(hovertemplate = 'Время: %{x}<br>Взаимодействий: %{y}')
fig.show()

В период 18 часов 57 минут и 18 часов 58 минут наблюдалось максимальное количество взаимодействий пользователей по всем темам карточек.

In [25]:
# построим график количества взаимодействий пользователей по темам карточек и времени с относительными значениями
fig = go.Figure()
for item in item_visits_time['item_topic'].unique():
    fig.add_trace(go.Scatter(x = item_visits_time.query('item_topic == @item')['dt'],
                             y = item_visits_time.query('item_topic == @item')['visits_count'],
                             mode = 'lines',
                             name = item,
                             stackgroup = 'one',
                             groupnorm = 'percent'))
fig.update_layout(yaxis = dict(range = [1, 102]),
                  title = 'Количество взаимодействий пользователей по темам карточек и времени (относительные значения)',
                  title_font = dict(family = 'sans serif', size = 20),
                  xaxis_title = 'Время',
                  yaxis_title = 'Процент взаимодействий',
                  showlegend = False,
                  margin = dict(l = 0, r = 20, t = 70, b = 0))
def annotation(y, text):
    fig.add_annotation(x = '18-55',
                       y = y,
                       text = text,
                       showarrow = False)
annotation_dict = {43 : 'Наука',
                   56 : 'Отношения',
                   22 : 'Интересные факты',
                   49 : 'Общество',
                   62 : 'Подборки',
                   82 : 'Россия',
                   68 : 'Полезные советы',
                   30 : 'История'}
for k, v in annotation_dict.items():
    annotation(k, v)
fig.add_annotation(x = '18-35', y = 5,
                   text='С 18-36 до 18-51 данные отсутствуют',
                   showarrow = True,
                   arrowhead = 1,
                   arrowsize = 1,
                   arrowwidth = 2,
                   arrowcolor = 'black',
                   font = dict(family = 'sans serif', size = 14, color = 'white'),
                   align = 'center',
                   bordercolor = 'royalblue',
                   borderwidth = 2,
                   borderpad = 4,
                   bgcolor = 'crimson',
                   opacity = 0.8)
fig.update_xaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_yaxes(title_font = dict(size = 18, family = 'sans serif'))
fig.update_traces(hovertemplate = 'Время: %{x}<br>Процент: %{y}')
fig.show()

Доля взаимодействий пользователей по темам карточек со временем практически не меняется.

In [26]:
# создадим таблицу с количеством взаимодействий пользователей по темам карточек и возрастным группам
item_age_visits = dash_visits.pivot_table(index = 'item_topic',
                                          columns = 'age_segment',
                                          values = 'visits',
                                          aggfunc = 'sum')                    
item_age_visits.head()
Out[26]:
age_segment 18-25 26-30 31-35 36-40 41-45 45+
item_topic
Деньги 4472 1950 1686 1302 502 379
Дети 5106 2006 1672 1260 585 360
Женская психология 3277 1501 1365 961 397 236
Женщины 4619 2258 2112 1488 620 402
Здоровье 4573 1941 1730 1250 505 400
In [27]:
# построим график количества взаимодействий пользователей по темам карточек и возрастным группам
fig = go.Figure()
x = item_age_visits.columns.to_list()
y = item_age_visits.index.to_list()
z = item_age_visits.values
fig = ff.create_annotated_heatmap(z, x = x, y = y, colorscale = 'ice')
fig.update_layout(title = 'Количество взаимодействий пользователей по темам карточек и возрастным группам',
                  title_font = dict(family = 'sans serif', size = 20),
                  margin = dict(l = 0, r = 20, t = 70, b = 0))
fig.update_traces(hovertemplate = 'Возрастная группа: %{x}<br>Тема карточек: %{y}<br>Взаимодействий: %{z}')
for i in range(len(fig.layout.annotations)):
    fig.layout.annotations[i].font.size = 11
fig.show()

У пользователей возрастной группы с 18 до 25 лет наибольшее количество взаимодействий на темы "Отношения", "Наука", "Общество" и "Интересные факты", у других возрастных групп предпочтения такие же, но наиболее популярными являются темы "Наука" и "Интересные факты".

In [28]:
# создадим таблицу с количеством взаимодействий пользователей по темам карточек и темам источников
item_source_visits = dash_visits.pivot_table(index = 'item_topic',
                                             columns = 'source_topic',                                             
                                             values = 'visits',
                                             aggfunc = 'sum')                    
item_source_visits = item_source_visits.fillna(0)
item_source_visits = item_source_visits.astype('int')
item_source_visits.head()
Out[28]:
source_topic Авто Деньги Дети Еда Здоровье Знаменитости Интерьеры Искусство История Кино ... Ремонт Россия Сад и дача Сделай сам Семейные отношения Семья Спорт Строительство Технологии Финансы
item_topic
Деньги 338 203 859 193 65 591 62 172 271 1042 ... 362 1132 101 137 696 345 134 68 88 415
Дети 192 228 621 675 346 1444 97 238 455 474 ... 174 547 633 354 1184 558 21 103 28 53
Женская психология 26 256 613 67 349 546 0 96 181 264 ... 13 660 49 19 2073 759 26 0 39 5
Женщины 156 122 875 348 1022 967 175 485 560 340 ... 67 397 125 223 2270 988 210 56 6 6
Здоровье 232 95 798 558 404 962 57 64 68 156 ... 145 712 542 548 814 247 197 106 74 19

5 rows × 26 columns

In [29]:
# построим график количества взаимодействий пользователей по темам карточек и темам источников
fig = go.Figure()
x = item_source_visits.columns.to_list()
y = item_source_visits.index.to_list()
z = item_source_visits.values
fig = ff.create_annotated_heatmap(z, x = x, y = y, colorscale = 'ice')
fig.update_layout(title = 'Количество взаимодействий пользователей по темам карточек и темам источников',
                  title_font = dict(family = 'sans serif', size = 20),
                  margin = dict(l = 0, r = 20, t = 170, b = 0))
fig.update_traces(hovertemplate = 'Тема источников: %{x}<br>Тема карточек: %{y}<br>Взаимодействий: %{z}')
for i in range(len(fig.layout.annotations)):
    fig.layout.annotations[i].font.size = 10
fig.show()

Наибольшее количество взаимодействий пользователей у карточек с темой "Рассказы" из источника "Путешествия", с темой "Общество" из источника "Россия" и с темой "Наука" из источника "Кино".

Общий вывод

Всего пользователями осуществлено 310207 взаимодействий, более 15000 взаимодействий осуществлено по 8 темам карточек, более 20000 - из источников по 6 темам.
Максимальное количество взаимодействий осуществлено пользователями с 18 часов 56 минут по 18 часов 59 минут, по карточкам с темами "Наука", "Отношения", "Интересные факты" и "Общество", из источников с темами "Семейные отношения", "Россия" и "Полезные советы", возрастной группы от 18 до 25 лет.
В период 18 часов 57 минут и 18 часов 58 минут наблюдалось максимальное количество взаимодействий пользователей по всем темам карточек, при этом доля взаимодействий пользователей по темам карточек со временем практически не меняется.
У пользователей возрастной группы с 18 до 25 лет наибольшее количество взаимодействий на темы "Отношения", "Наука", "Общество" и "Интересные факты", у других возрастных групп предпочтения такие же, но наиболее популярными являются темы "Наука" и "Интересные факты".
Наибольшее количество взаимодействий пользователей по карточкам с темами "Рассказы" из источника "Путешествия", с темами "Общество" из источника "Россия" и с темами "Наука" из источника "Кино".

По ссылке презентация опубликована в открытом доступе.

Рекомендации

  1. При планировании рекламных кампаний учесть, что пиковое время взаимодействия пользователей с системой с 18 часов 56 минут по 18 часов 59 минут.
  2. Наибольшее внимание уделить продвижению карточек на темы "Наука", "Отношения", "Интересные факты" и "Общество".
  3. В первоочередном порядке развивать источники с темами "Семейные отношения", "Россия" и "Полезные советы".
  4. Максимально расширить спектр карточек с темой «Рассказы» из источника «Путешествия», с темой «Общество» из источника «Россия» и с темой «Наука» из источника «Кино».
  5. Адаптировать дизайн карточек и их наполнение под молодую аудиторию.